import { Injectable } from '@angular/core';
import * as childProcess from 'child_process';

// If you import a module but never use any of the imported values other than as TypeScript types,
// the resulting javascript file will look as if you never imported the module at all.
import { ipcRenderer, remote, shell, webFrame } from 'electron';

import * as fs from 'fs';

import { EncodingConstant } from '../constants/encoding.constant';
import { IpcMessageConstant } from '../constants/ipc-message.constant';
import { CommonService } from './common.service';

const { dialog } = require('electron').remote;

@Injectable()
export class ElectronService {
    ipcRenderer: typeof ipcRenderer;
    webFrame: typeof webFrame;
    remote: typeof remote;
    childProcess: typeof childProcess;
    fs: typeof fs;

    get isElectron(): boolean {
        return !!(window && window.process && window.process.type);
    }

    constructor(private commonService: CommonService) {
        // Conditional imports
        if (this.isElectron) {
            this.ipcRenderer = window.require('electron').ipcRenderer;
            this.webFrame = window.require('electron').webFrame;
            this.remote = window.require('electron').remote;

            this.childProcess = window.require('child_process');
            this.fs = window.require('fs');
        }
    }

    /**
     * Gets app path with provided name.
     */
    getPath(name: string): string {
        return ipcRenderer.sendSync(IpcMessageConstant.getPath, name);
    }

    /**
     * This is an example to show how we interact with ipc async message.
     * 
     * When we send an async message we prepare the replay message with random numbers.
     * Then we setup an once message listener to handle the reply.
     * 
     * This can handle the concurrency.
     */
    sendAsynchronousMessage(callback: (result) => void): void {
        let relpyMessage = `asynchronous-message-reply-${this.commonService.getRandomNumberWithinRange(1000, 9999)}`;

        ipcRenderer.send('asynchronous-message', relpyMessage);

        // Adds a one time listener function for the event. This listener is invoked only the next time a message is sent to channel, after which it is removed.
        ipcRenderer.once(relpyMessage, (result) => { });
    }

    openExternal(): void {
        shell.openExternal('file://D:/Temp/2019年工作总结(1).docx');
    }

    showOpenDialog(): void {
        let result = dialog.showOpenDialogSync(remote.getCurrentWindow(), { properties: ['openFile', 'createDirectory'] });

        console.dir(result);

        // this.ipcRenderer.send('showOpenDialog', {
        //     type: 'info'
        // });
    }

    showSaveDialogSync(): string {
        return dialog.showSaveDialogSync(remote.getCurrentWindow(), { properties: ['createDirectory'] });
    }

    /**
     * Reads binary file and return the buffer data via callback.
     * 
     * How to use Buffers in nodejs? Check on https://nodejs.org/en/knowledge/advanced/buffers/how-to-use-buffers/
     */
    async readFile(fileFullName: string, callback: (buffer: Buffer) => void): Promise<void> {
        fs.readFile(fileFullName, (err, data) => {
            if (err) {
                throw err;
            }

            if (!this.commonService.isNullOrUndefined(callback)) {
                callback(data);
            }
        });
    }

    /**
     * Gets the text file path from dialog and asynchronously reads the entire contents from the file.
     */
    async readTextFile(callback: (content: string) => void): Promise<void> {
        let dialogResult = await dialog.showOpenDialog(remote.getCurrentWindow(), { properties: ['openFile', 'createDirectory'] });

        if (!this.commonService.isNullOrUndefined(dialogResult.filePaths) && dialogResult.filePaths.length > 0) {
            fs.readFile(dialogResult.filePaths[0], EncodingConstant.utf8, (err, data) => callback(data));
        }
    }

    /**
     * Gets the file path from dialog and synchronously reads the entire contents from the file.
     */
    readTextFileSync(): string {
        let content: string = '';
        let filenames = dialog.showOpenDialogSync(remote.getCurrentWindow(), { properties: ['openFile', 'createDirectory'] });

        if (!this.commonService.isNullOrUndefined(filenames) && filenames.length > 0) {
            content = fs.readFileSync(filenames[0], EncodingConstant.utf8);
        }

        return content;
    }

    writeTextFileSync(content: string): void {
        dialog.showSaveDialog(remote.getCurrentWindow(), { properties: ['showOverwriteConfirmation'] }).then((p) => {
            if (!this.commonService.isNullOrUndefinedOrEmptyString(p.filePath)) {
                content = `${content} at ${this.commonService.getCurrentDate()}`;

                fs.writeFileSync(p.filePath, content);
            }
        });
    }

    deleteFileSync(filePath: string): void {
        if (fs.existsSync(filePath)) {
            fs.unlinkSync(filePath);
        }
    }
}
